package com.wanghua.spring.listeners.singleton;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.util.HashMap;
import java.util.Map;

public class LoginSessionListener implements HttpSessionAttributeListener {
    Log log = LogFactory.getLog(this.getClass());

    //存储登录用户的session信息。单态登录主要靠这个。因为它的 key 是用户名，value是 session。表示一个用户只有一个session在系统中。
    Map<String, HttpSession> map = new HashMap<String, HttpSession>();

    public void attributeAdded(HttpSessionBindingEvent event) {
        String name = event.getName();
        if (name.equals("personInfo")) {
            PersonInfo personInfo = (PersonInfo) event.getValue();
            if (map.get(personInfo.getAccount()) != null) {  //已经登录了
                HttpSession session = map.get(personInfo.getAccount());
                PersonInfo oldPersonInfo = (PersonInfo) session.getAttribute("personInfo");
                log.info("帐号" + oldPersonInfo.getAccount() + "在" + oldPersonInfo.getIp() + "已经登录，该登录将被迫下线。");

                //已经登录了，就从session中删除personInfo，当然也可以直接删除session。但是这个例子需要向之前的登录者传递被迫下线的信息，所以保留session作为载体。
                session.removeAttribute("personInfo");  //会触发 attributeRemoved 方法。
                session.setAttribute("msg", "您的帐号已经在其他机器上登录，您被迫下载。");
            }

            //将新 Session 以用户名为索引，放入 Map。
            map.put(personInfo.getAccount(), event.getSession());
            log.info("帐号" + personInfo.getAccount() + "在" + personInfo.getIp() + "登录");
        }
    }

    public void attributeRemoved(HttpSessionBindingEvent event) {
        String name = event.getName();
        if (name.equals("personInfo")) {
            PersonInfo personInfo = (PersonInfo) event.getValue();
            map.remove(personInfo.getAccount());   //从 map 中删除登录信息。
            log.info("帐号" + personInfo.getAccount() + "注销");
        }
    }

    // singleton.jsp 页面不会用到此事件的。
    public void attributeReplaced(HttpSessionBindingEvent event) {
        String name = event.getName();
        if (name.equals("personInfo")) {
            PersonInfo oldPersonInfo = (PersonInfo) event.getValue();
            map.remove(oldPersonInfo.getAccount());
            PersonInfo personInfo = (PersonInfo) event.getSession().getAttribute("personInfo");
            if (map.get(personInfo.getAccount()) != null) {
                HttpSession session = map.get(personInfo.getAccount());
                session.removeAttribute("personInfo");
                session.setAttribute("msg", "您的帐号已经在其他机器上登录，您被迫下线。");
            }
            map.put("personInfo", event.getSession());
        }
    }
}
